package cn.murky.admin.quartz.utils;

import cn.murky.admin.quartz.constant.ScheduleConstants;
import cn.murky.admin.quartz.domain.entity.SysJob;
import cn.murky.admin.quartz.domain.entity.SysJobLog;
import cn.murky.admin.quartz.enums.SysJobLogStatus;
import cn.murky.admin.quartz.service.ISysJobLogService;
import org.noear.snack.ONode;
import org.noear.solon.Solon;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.OffsetDateTime;
import java.util.Date;
import java.util.concurrent.Callable;

/**
 * 抽象quartz调用
 *
 * @since ruoyi
 */
public abstract class AbstractQuartzJob implements Job
{
    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);

    /**
     * 线程本地变量
     */
//    private static ThreadLocal<OffsetDateTime> threadLocal = new ThreadLocal<>();
    public static ScopedValue<OffsetDateTime> OFFSETDATETIME_SCOPED = ScopedValue.newInstance();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException
    {
        ONode onode = ONode.load(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
        SysJob sysJob = onode.toObject(SysJob.class);
        try
        {
            before(context, sysJob,()->{
                if (sysJob != null)
                {
                    doExecute(context, sysJob);
                }
                after(context, sysJob, null);
                return null;
            });

        }
        catch (Exception e)
        {
            log.error("任务执行异常  - ：", e);
            after(context, sysJob, e);
        }
    }

    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     */
    protected void before(JobExecutionContext context, SysJob sysJob, Callable callable) throws Exception {
        ScopedValue.callWhere(OFFSETDATETIME_SCOPED, OffsetDateTime.now(), callable);
    }

    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     */
    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
    {
        OffsetDateTime startTime = OFFSETDATETIME_SCOPED.get();

        final SysJobLog sysJobLog = new SysJobLog();
        sysJobLog.setJobName(sysJob.getJobName());
        sysJobLog.setJobGroup(sysJob.getJobGroup().getCode().toString());
        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
        sysJobLog.setStartTime(startTime);
        sysJobLog.setStopTime(OffsetDateTime.now());
        long runMs = sysJobLog.getStopTime().toInstant().toEpochMilli() - sysJobLog.getStartTime().toInstant().toEpochMilli();
        sysJobLog.setJobMessage(STR."\{sysJobLog.getJobName()} 总共耗时：\{runMs}毫秒");
        if (e != null)
        {
            sysJobLog.setStatus(SysJobLogStatus.FAIL);
            sysJobLog.setExceptionInfo(e.getMessage());
        }
        else
        {
            sysJobLog.setStatus(SysJobLogStatus.SUCCESS);
        }
        sysJobLog.setCreateUser(1L);
        // 写入数据库当中
        Solon.context().getBean(ISysJobLogService.class).save(sysJobLog);

    }

    /**
     * 执行方法，由子类重载
     *
     * @param context 工作执行上下文对象
     * @param sysJob 系统计划任务
     * @throws Exception 执行过程中的异常
     */
    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
}
